#include "Capture.h"
#include <functional>
#include "ScreenCapture9.h"
#include "AudioCapThread.h"
typedef std::function<void(int type, const char *msg)> func_callback;
class GDIWindowArea
{
	HWND _hwnd = NULL;
	HDC _dc = NULL;
	HDC _hCaptureDC = NULL;
	HBITMAP _bitmap = NULL;
	BITMAPINFOHEADER _bmiHeader;
	uint8_t *_pData = NULL;
public:
	~GDIWindowArea()
	{
		if (_hwnd != NULL)
			ReleaseDC(_hwnd, _dc);
		if (_hCaptureDC != NULL)
			DeleteDC(_hCaptureDC);
		if (_pData != NULL)
			delete[]_pData;
	}

#define WIDTHBYTES(bits) ((DWORD)(((bits)+31) & (~31)) / 8)
#define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((DWORD)(bi).biWidth * (DWORD)(bi).biBitCount)
#define DIBSIZE(bi) ((bi).biHeight < 0 ? (-1)*(_DIBSIZE(bi)) : _DIBSIZE(bi))
#define _DIBSIZE(bi) (DIBWIDTHBYTES(bi) * (DWORD)(bi).biHeight)
	DWORD GetBitmapSize_1(const BITMAPINFOHEADER *pHeader)
	{
		return DIBSIZE(*pHeader);
	}
	int _w;
	int _h;
public:
	int Initialize(HWND hwnd)
	{

		RECT rect;
		GetClientRect(hwnd, &rect);

		_w = rect.right - rect.left;
		_h = rect.bottom - rect.top;
		int x = _w % 16;
		if (x > 0)
			_w -= x;

		if (_h % 2 != 0)
			_h--;

		if (_pData != NULL)
			delete[]_pData;
		_pData = new BYTE[_w* _h * 3];
		_bmiHeader.biCompression = BI_RGB;
		_bmiHeader.biBitCount = 24;
		_bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		_bmiHeader.biWidth = _w;
		_bmiHeader.biHeight = -_h;
		//bmiHeader.biHeight = -m_iImageHeight;
		_bmiHeader.biPlanes = 1;
		_bmiHeader.biSizeImage = GetBitmapSize_1(&_bmiHeader);
		_bmiHeader.biClrImportant = 0;
		_bmiHeader.biXPelsPerMeter = 0;
		_bmiHeader.biYPelsPerMeter = 0;
		if (hwnd != NULL)
		{
			if (_dc != NULL)
				ReleaseDC(_hwnd, _dc);

			_dc = GetDC(hwnd);
			//_dc = GetWindowDC(hwnd)
			if (_hCaptureDC != NULL)
				DeleteDC(_hCaptureDC);
			_hCaptureDC = CreateCompatibleDC(_dc);

			if (_bitmap != NULL)
				DeleteObject(&_bitmap);
			_bitmap = CreateCompatibleBitmap(_dc, _w, _h);
			SelectObject(_hCaptureDC, _bitmap);
			return 0;
		}
		return -1;
	}
	uint8_t * GetData()
	{
		BitBlt(_hCaptureDC, 0, 0, _w, _h, _dc, 0, 0, SRCCOPY);// or $40000000 );
		GetDIBits(_hCaptureDC, _bitmap, 0, _h, _pData, (BITMAPINFO *)&(_bmiHeader), DIB_RGB_COLORS);
		return _pData;
	}

};

class ScreenArea
{
public:
	int _w = 1920;
	int _h = 1080;
	int _dw = 1280;
	int _dh = 720;


public:
	~ScreenArea()
	{

	}
	int64_t _vpts = 0;
	ScreenCapture9 _screenCap;

	std::string _serverurl;

	int Initialize(HWND hwnd, int nDisplay /*,RECT &rect*/)
	{
		int display = _screenCap.InitDisplayCount();
		//HWND hwnd = GetDesktopWindow();
		_screenCap.InitD3D(hwnd, nDisplay);
		return display;
	}


	int RGB2YUV()
	{
	}



};


CAPTUREAV_EXPORT  void CaptureAV::Init()
{
	CoInitialize(NULL);
}
CAPTUREAV_EXPORT  void CaptureAV::UnInit()
{
	CoUninitialize();
}
CaptureAV::CaptureAV()
{

}
CaptureAV::~CaptureAV()
{

}


class Capture_AV1 :public CaptureAV
{
private:
	GDIWindowArea _area;
	int _dw = 1280;
	int _dh = 720;
	int _video_index = 0;
	int _video_w = 320;
	int _video_h = 240;
	CAudioCapThread _audio;
	//DeviceAudio _audio;
public:
	void      CaptureDesktopSet(int w, int h)
	{
		_dw = w;
		_dh = h;
	}
	uint8_t* CaptureDesktopGet(size_t &size)
	{
		return NULL;
	}
	int      CaptureAV::CaptureAppSet(HWND hwnd)
	{
		return _area.Initialize(hwnd);
	}
	uint8_t* CaptureAV::CaptureAppGet()
	{
		return _area.GetData();
	}

	void      CaptureAV::CaptureVideoSet(int index, int w, int h)
	{

	}
	uint8_t* CaptureAV::CaptureVideoGet()
	{
		return NULL;
	}


	void CaptureAV::SetAudioCallback(VoiceCallback callback)
	{
		_audio.m_callback = callback;
	}

	//Audio_Data * CaptureAV::CaptureAudioGet()
	//{
	//	Audio_Data * ad = _audio.GetAudio();
	//	return ad;
	//}
	void CaptureAV::StartAudio(int index)
	{
		if (index == 0)
			_audio.SetDeiveType(CAudioCapThread::SPEAKER);
		else
			_audio.SetDeiveType(CAudioCapThread::MICPHONE);
//		_audio.Init();
		_audio.Start();
	}
	void StopAudio()
	{
		_audio.Stop();
	}
	void JoinAudio()
	{
		_audio.Join();
	}

};
CAPTUREAV_EXPORT CaptureAV* CaptureAV_Create()
{
	return new Capture_AV1();
}
CAPTUREAV_EXPORT void CaptureAV_Release(CaptureAV * av)
{
	if (av == NULL)
		return;
	delete av;
}
